package com.gameShare.service.misc

import com.gameShare.constances.FilePaths
import com.gameShare.enums.misc.HttpContentTypeEnum
import com.gameShare.enums.misc.ResponseCodeEnum
import com.gameShare.exceptions.BusinessException
import com.gameShare.utils.StringUtils
import jakarta.servlet.http.HttpServletResponse
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.OutputStream
import java.nio.file.Files
import java.nio.file.Paths

@Service
class FileService(private val filePaths: FilePaths ) {

    private val log: Logger = LoggerFactory.getLogger(FileService::class.java)

    /**
     * 获取服务器文件
     * 将文件写入httpResponse体内返回给前端
     * @param httpResponse http响应体
     * @param path 文件路径
     * @param contentTypeEnum 文件类型
     * @param cacheExpireTime 缓存失效时间
     */
    private fun readFileToResponse(httpResponse : HttpServletResponse,path : String, contentTypeEnum: HttpContentTypeEnum, cacheExpireTime : Int){
        // 防止遍历攻击，不允许访问上级目录
        StringUtils.checkPathIsOk(path)
        val suffix = getFileSuffix(path)

        httpResponse.contentType = "${contentTypeEnum.type}/$suffix"
        httpResponse.setHeader("Cache-Control", "max-age=$cacheExpireTime")
        val filePath = filePaths.linkPath(arrayOf(path))

        try {
            // 打开文件输入流
            val file = File(filePath)
            val inputStream = FileInputStream(file)
            val outputStream: OutputStream = httpResponse.outputStream

            // 读取文件内容并写入响应体
            val buffer = ByteArray(4096)
            var bytesRead: Int
            while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                outputStream.write(buffer, 0, bytesRead)
            }

            // 关闭流
            inputStream.close()
            outputStream.flush()
            outputStream.close()
        } catch (e: Exception) {
            log.error("读取文件${filePath}失败,文件可能不存在", e)
            httpResponse.contentType = ""
            throw BusinessException(ResponseCodeEnum.NOT_FIND)
        }
    }

    fun readImages(httpResponse : HttpServletResponse,path : String, contentTypeEnum: HttpContentTypeEnum, cacheExpireTime : Int){
        if (!filePaths.imagePaths.contains(path.split("/").first()))
            throw BusinessException(ResponseCodeEnum.ARGUMENT_ERROR)
        readFileToResponse(httpResponse, path, contentTypeEnum, cacheExpireTime)
    }

    fun readFileToByte(filePath: String): ByteArray? {
        return try {
            Files.readAllBytes(Paths.get(filePath))
        } catch (e: Exception) {
            log.error("读取${filePath}文件失败", e)
            throw FileNotFoundException("严重异常：验证码图片不存在,路径为${filePath}")
        }
    }


    /**
     * 读取一个目录下所有文件
     *
     * @param filePath 目录地址
     * @return File
     */
    fun readDirAllFiles(filePath: String): List<File> {
        return File(filePath).takeIf { it.isDirectory }?.let {
            it.listFiles()
                ?.filter { file -> file.isFile }
        } ?: emptyList()
    }

    companion object{
        /**
         * 获取文件的后缀
         *
         * @param fileName 文件名
         * @return 后缀如果没有则返回''
         */
        fun getFileSuffix(fileName : String): String {
            return if (fileName.isEmpty() || !fileName.contains(".")) ""
            else fileName.substring(fileName.lastIndexOf(".") + 1)
        }

        fun getFilePrefix(fileName: String): String {
            return if (fileName.isEmpty() || !fileName.contains("."))  fileName
            else  fileName.substring(0, fileName.lastIndexOf("."))
        }
    }
}